#ifndef HTTPSERVER_HPP
#define HTTPSERVER_HPP

#include <iostream>

#include <string>

#include <pthread.h>

#include "TcpSocket.hpp"

#include "log.hpp"

#include <vector>

#include <fstream>

#include <unordered_map>

#include <sstream>

/* httpserver.hpp */

const std::string wwwroot = "./wwwroot";

const std::string sep = "\r\n";

const std::string homepage = "index.html";

class HttpServer;

class HttpRequest
// 将协议进行按行解析
{
public:
    HttpRequest()
    {
    }

    void Deserialize(std::string req)
    {
        while (true)
        {
            std::size_t pos = req.find(sep);
            if (pos == std::string::npos)
                break; // 不存在或已找完
            std::string temp = req.substr(0, pos);
            if (temp.empty())
                break; // 空行

            req_header.push_back(temp); // 存到vector容器中
            req.erase(0, pos + sep.size());
        }
        text = req;
    }

    void Parse()
    {
        std::stringstream ss(req_header[0]); // req_header 中0号下标数据为请求行
        ss >> method >> url >> http_version; // 将请求行使用stringstream进行二次解析
        resource_path = wwwroot;
        if (url == "/" || url == "/index.html") // 判断是否响应回浏览器主页资源
        {
            resource_path += "/";
            resource_path += homepage;
        }
        else
            resource_path += url; // /a/b/c/d/e.html -> ./wwwroot/a/b/c/d/e.html

        auto pos = resource_path.rfind("."); // 由后向前找
        if (pos == std::string::npos)
        {
            suffix = ".html";
        }
        else
        {
            suffix = resource_path.substr(pos);
        }
    }

    void DebugPrint()
    { // Debug 打印解析后的协议
        std::cout << "##############################" << std::endl;

        std::cout << "------------------------------" << std::endl;
        for (auto &sub : req_header)
        {
            std::cout << sub << std::endl;
        }
        std::cout << text << std::endl;

        std::cout << "请求方法: " << method << std::endl;
        std::cout << "请求路径: " << url << std::endl;
        std::cout << "协议版本: " << http_version << std::endl;
        std::cout << "实际访问: " << resource_path << std::endl;

        std::cout << "------------------------------" << std::endl;
        std::cout << "##############################" << std::endl;
    }

public:
    std::vector<std::string> req_header; // 请求报头
    std::string text;                    // 正文内容

    std::string method;       // 请求方法
    std::string url;          // 路径
    std::string http_version; // 协议版本

    std::string resource_path; // 实际访问路径
    std::string suffix;        // 后缀

};

class HttpServer
{
public:

    HttpServer(uint16_t port = defaultport) : port_(port)
    {
        
        ContentTable = {{".png", "image/png"}, {".mp4", "video/mp4"}, {".html", "text/html"}}; // 导入参照表
    }

    ~HttpServer() {}

    // 服务器启动函数(包括初始化)
    bool Start()
    {
        listensock_.Socket();
        listensock_.Bind(port_);
        listensock_.Listen();
        for (;;)
        {
            std::string clientip;
            uint16_t clientport;
            int sockfd = listensock_.Accept(&clientip, &clientport);
            pthread_t tid;
            ThreadData *td = new ThreadData(sockfd, this);
            pthread_create(&tid, nullptr, ThreadRun, td);
        }
    }

    // 线程入口函数
    static void *ThreadRun(void *args)
    {
        ThreadData *td = static_cast<ThreadData *>(args);
        pthread_detach(pthread_self());
        td->svr_->HandlerHttp(td->sockfd_);
        delete td;
        return nullptr;
    }

    // // 单独封装处理工作
    // static void HandlerHttp(int sockfd)
    // {
    //     char buffer[10240];
    //     ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
    //     if (n > 0)
    //     {
    //         buffer[n] = 0;
    //         std::cout << buffer; // 为服务端打印出请求信息

    //         // 返回响应
    //         std::string line_feed = "\r\n";                                // 换行
    //         std::string text = "hello";                                    // 响应正文
    //         std::string response_line = "HTTP/1.0 200 OK" + line_feed;     // 响应行 (包含协议版本 状态码 状态码描述)
    //         std::string response_header = "Content-Length: ";              // 响应正文长度(报头字段)
    //         response_header += std::to_string(text.size());                // 为正文长度添加属性
    //         response_header += line_feed;                                  // 换行
    //         std::string blank_line = "\r\n";                               // 设置空行
    //         response_header += line_feed;                                  // 添加空行
    //         std::string response = response_line + response_header + text; // 组装响应

    //         // 发送响应
    //         send(sockfd, response.c_str(), response.size(), 0);
    //     }

    //     close(sockfd);
    // }

    std::string SuffixToDesc(const std::string &suffix)
    {
        return ContentTable[suffix];
    }

    // static std::string ReadHtmlContent(const std::string &path)
    // {
    //     // 读取文件内容

    //     // std::ifstream in(path + "/index.html");

    //     std::ifstream in(path, std::ios_base::binary);
    //     if (!in.is_open()) // 打开失败返回 "404"
    //     {
    //         // return "404";
    //         return ""; // 返回空串
    //     }

    //     std::string content;

    //     // std::string line;
    //     // while (std::getline(in, line))
    //     // { // 使用 getline 对文件内容进行按行读取
    //     //     content += line;
    //     // }

    //     in.seekg(0, std::ios_base::end);
    //     auto len = in.tellg();
    //     in.seekg(0, std::ios_base::beg);
    //     in.close();

    //     content.resize(len);
    //     in.read((char*)content.c_str(),content.size());
    //     return content;
    // }

    static std::string ReadHtmlContent(const std::string &path)
    {
        // 尝试以二进制模式打开文件
        std::ifstream in(path, std::ios_base::binary);

        // 如果文件打开失败，返回一个空字符串
        if (!in.is_open())
        {
            return ""; // 返回空串
        }

        // 定义一个内容字符串，用于存储文件内容
        std::string content;

        // 定位到文件末尾，以便计算文件长度
        in.seekg(0, std::ios_base::end);
        auto len = in.tellg();           // 获取文件长度
        in.seekg(0, std::ios_base::beg); // 定位回文件开头

        // 调整内容字符串的大小以容纳文件内容
        content.resize(len);

        // 读取文件内容到字符串
        in.read((char *)content.c_str(), content.size() + 1);

        // 关闭文件
        in.close();

        // 返回文件内容
        return content;
    }

    // 单独封装处理工作
    void HandlerHttp(int sockfd)
    {
        char buffer[10240];
        ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            // std::cout << buffer; // 为服务端打印出请求信息
            HttpRequest request;
            request.Deserialize(buffer); // 第一次解析
            request.Parse();             // 对请求行进行解析
            request.DebugPrint();        // debug打印

            // 返回响应
            std::string line_feed = "\r\n"; // 换行
            std::string text;
            bool ok = true;                                // 设置变量用于条件判断从而修改返回响应时能够返回对应的状态码
            text = ReadHtmlContent(request.resource_path); // 调用函数对文件进行读取                  // 响应正文
            if (text.empty())
            { // 当返回的为空串时则表示访问资源不存在 返回响应时返回对应的404页面即可
                std::string err_html = wwwroot;
                err_html += "/";
                err_html += "err.html";
                text = ReadHtmlContent(err_html);
                ok = false;
            }
            std::string response_line;

            // 根据条件变量状态来返回不同的状态码
            if (ok)
                response_line = "HTTP/1.0 200 OK" + line_feed;
            // response_line = "HTTP/1.0 302 Found" + line_feed;
            else
                response_line = "HTTP/1.0 404 Not Found" + line_feed;
            // 响应行 (包含协议版本 状态码 状态码描述)
            std::string response_header = "Content-Length: "; // 响应正文长度(报头字段)
            response_header += std::to_string(text.size());   // 为正文长度添加属性
            response_header += line_feed;                     // 换行
            response_header += "Set-Cookie: ";                // 添加Set-Cookie头部并设置属性
            response_header += "name=helloworld";
            response_header += line_feed;                    // 换行
            response_header += "Content-Type: ";             // 增加Content-Type头部
            response_header += SuffixToDesc(request.suffix); // 增加Content-Type属性
            response_header += line_feed;                    // 换行
            response_header += "Location: https://www.baidu.com";
            response_header += line_feed; // 换行

            std::string blank_line = "\r\n";                               // 设置空行
            response_header += line_feed;                                  // 添加空行
            std::string response = response_line + response_header + text; // 组装响应

            // 发送响应
            send(sockfd, response.c_str(), response.size(), 0);
        }

        close(sockfd);
    }

    // 包含线程所需数据的内部类
    class ThreadData
    {
    public:
        ThreadData(int sockfd, HttpServer *svr) : sockfd_(sockfd), svr_(svr) {}

    public:
        int sockfd_;
        HttpServer *svr_;
    };

private:
    uint16_t port_;                    // 端口号
    static const uint16_t defaultport; // 默认端口号
    NetSocket listensock_;             // 监听端口

    std::unordered_map<std::string, std::string> ContentTable; // 文件后缀参照表
};
const uint16_t HttpServer::defaultport = 8049; // 静态成员的初始化
#endif